#include <iostream>

#include "SerialManager.h"
#include "spdlog/spdlog.h"
#include "rxcpp/rx.hpp"
#include "boost/program_options.hpp"
#include <regex>
#include <random>
#include <unistd.h>

namespace Rx{
    using namespace rxcpp;
    using namespace rxcpp::sources;
    using namespace rxcpp::operators;
    using namespace rxcpp::util;

}

using namespace Rx;
using namespace std;
using namespace std::chrono;

namespace opt = boost::program_options;


std::vector<uint8_t> getInstruct(uint8_t action, std::vector<uint8_t> data){
    size_t dataLength = data.size();
    std::vector<uint8_t> instruct;
    instruct.push_back(0x55);
    instruct.push_back(0x00);
    instruct.push_back(0xFF);
    instruct.push_back(action);
    instruct.push_back(dataLength&0xFF);
    spdlog::info("data size -> {}", data.size());
    instruct.insert(instruct.end(), data.begin(), data.end());
    uint8_t check = 0x55;
    for (size_t i = 1; i < instruct.size(); ++i) {
        check = check ^ instruct[i];
    }
    instruct.push_back(check);
    instruct.push_back(0xAA);
    return instruct;
}

int main(int argc, char const *argv[]) {
    spdlog::set_pattern("[%H:%M:%S %z] [%n] [%^---%L---%$] [thread %t] %v");
    spdlog::info("App Start ...");

    SerialManager serialManager;
    serialManager.enumeratePorts();

    opt::options_description desc("BA200 Linux Application");
    desc.add_options()("HELP,h", "帮助");
    desc.add_options()("RESET", "复位");
    desc.add_options()("TRAY_OUT", "出仓");
    desc.add_options()("TRAY_IN", "入仓");
    desc.add_options()("TRAY_TO_SCANNER", "移动至扫码位置");
    desc.add_options()("TRAY_STATE", "查询托盘状态");
    desc.add_options()("TRAY_TO_HGB", "移动至HGB位置");
    desc.add_options()("TRAY_POSITION", "查询托盘位置");
    desc.add_options()("DETECT_HGB", "检测HGB");
    desc.add_options()("LED_OPEN", "打开补光灯");
    desc.add_options()("LED_CLOSE", "关闭补光灯");
    desc.add_options()("TRIAXIAL_RESET", "三轴复位");
    desc.add_options()("RESTORE_PROFILE", "恢复默认参数");
    desc.add_options()("MOVE_SCANNING", "移动扫码");

    opt::variables_map vm;
    opt::store(opt::parse_command_line(argc, argv, desc), vm);
    opt::notify(vm);
    if (vm.empty() || vm.count("HELP")) {
        std::cout << desc << std::endl;
        return 0;
    } else if (vm.count("RESET")) {
        serialManager.action(RESET);
    } else if (vm.count("TRAY_OUT")) {
        serialManager.action(TRAY_OUT);
    } else if (vm.count("TRAY_IN")) {
        serialManager.action(TRAY_IN);
    } else if (vm.count("TRAY_TO_SCANNER")) {
        serialManager.action(TRAY_TO_SCANNER);
    } else if (vm.count("TRAY_STATE")) {
        serialManager.action(TRAY_STATE);
    } else if (vm.count("TRAY_TO_HGB")) {
        serialManager.action(TRAY_TO_HGB);
    } else if (vm.count("TRAY_POSITION")) {
        serialManager.action(TRAY_POSITION);
    } else if (vm.count("DETECT_HGB")) {
        serialManager.action(DETECT_HGB);
    } else if (vm.count("LED_OPEN")) {
        serialManager.action(LED_OPEN);
    } else if (vm.count("LED_CLOSE")) {
        serialManager.action(LED_CLOSE);
    } else if (vm.count("TRIAXIAL_RESET")) {
        serialManager.action(TRIAXIAL_RESET);
    } else if (vm.count("RESTORE_PROFILE")) {
        serialManager.action(RESTORE_PROFILE);
    } else if (vm.count("MOVE_SCANNING")) {
        serialManager.action(MOVE_SCANNING);
    }










//   rxcpp::observable<>::create<int>([](rxcpp::subscriber<int> subscriber)
//                                   {
//                                     for (int i = 0; i < 3; i++)
//                                     {
//                                         spdlog::info("create ...");
//                                         subscriber.on_next(i);
//                                     }
//                                 })
//        .subscribe_on(rxcpp::observe_on_event_loop())
//        .observe_on(rxcpp::observe_on_event_loop())
//        .subscribe( [](int i)
//                {
//                   spdlog::info("subscribe ...");
//                }
//                );

  auto test1 = rxcpp::observable<>::create<int>([](const rxcpp::subscriber<int>& subscriber)
                                 {
                                     for (int i = 0; i < 3; i++)
                                     {
                                         spdlog::info("create1 ...");
                                         subscriber.on_next(i);
                                     }
                                 });

  auto test2 = rxcpp::observable<>::create<int>([](const rxcpp::subscriber<int>& subscriber)
                                 {
                                     for (int i = 0; i < 3; i++)
                                     {
                                         spdlog::info("create3... ");
                                         subscriber.on_next(i);
                                     }
                                 });

//  test1.merge(test2)
//        .subscribe_on(rxcpp::observe_on_event_loop())
//        .observe_on(rxcpp::observe_on_event_loop())
//        .subscribe( [](int i)
//                {
//                   spdlog::info("subscribe ...");
//                }
//                );

    spdlog::info("App End ...");
    return 0;
}
